package com.wlyuan.index.domain.source;

import com.wlyuan.core.domain.valueobj.*;
import com.wlyuan.core.named.TrackType;
import com.wlyuan.index.domain.source.valueobj.Character;
import com.wlyuan.index.domain.source.valueobj.*;
import com.wlyuan.index.domain.source.valueobj.Statistics;
import com.wlyuan.tools.utils.CallUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@AllArgsConstructor
@Builder
@Getter
@ToString
public class Combine {

    @AllArgsConstructor
    @Getter
    @Builder
    @ToString
    public static class Waybill {
        private ContractNo contractNo;
        private CustomerId customerId;
        private String customerName;
        private WaybillId waybillId;
    }


    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    @Builder
    @Getter
    @ToString
    public static final class Close {
        @ApiModelProperty("关单原因")
        private String reason;

        @ApiModelProperty("关单类型")
        private Integer type;

        @ApiModelProperty("关单状态 10撤回中, 20待审核, 30拒绝中,40拒绝,50关单中，60同意")
        private Integer status;

        @ApiModelProperty("租户ID: 发起租户")
        private Long tenantId;
    }

    @AllArgsConstructor
    @Builder
    @Getter
    @ToString
    public static final class Device {
        @ApiModelProperty("设备编号")
        private DeviceCode deviceCode;

        @ApiModelProperty("湿度")
        private Boolean humidity;

        @ApiModelProperty("温度")
        private Boolean temperature;
    }

    @RequiredArgsConstructor
    @AllArgsConstructor
    @Getter
    @Builder
    @ToString
    public static class Relation {
        private final Character character;
        private final CombineStatus status;
        private final TenantId tenantId;
        private final Boolean endQuote;
        private List<Highlight> highlights;

        public Relation(Relation relation) {
            this.character = relation.character;
            this.status = relation.status;
            this.endQuote = relation.endQuote;
            this.tenantId = relation.tenantId;
            this.highlights = relation.highlights;
        }

        public void addHighlight(Highlight highlight, Integer quantity) {
            if (null == quantity || quantity <= 0) {
                return;
            }
            synchronized (this) {
                if (null == this.highlights) {
                    this.highlights = new ArrayList<>();
                }
            }
            this.highlights.add(highlight);
        }
    }

    @ApiModelProperty("合单ID")
    private CombineId combineId;
    @ApiModelProperty("合同号")
    private ContractNo contractNo;
    @ApiModelProperty("发货时间")
    private LocalDateTime fromTime;
    @ApiModelProperty("到货时间")
    private LocalDateTime toTime;
    @ApiModelProperty("跟踪单号")
    private String trackNo;
    @ApiModelProperty("跟踪方式")
    private TrackType trackType;
    @ApiModelProperty("发货方")
    private Customer customer;
    @ApiModelProperty("承运方")
    private Carrier carrier;
    @ApiModelProperty("运单列表")
    private List<Waybill> waybills;
    @ApiModelProperty("设备信息")
    private Device device;
    @ApiModelProperty("报价信息")
    private Quote quote;
    @ApiModelProperty("关单信息")
    private Close close;
    @ApiModelProperty("物品统计")
    private Statistics statistics;
    @ApiModelProperty("是否过关账期")
    private Boolean endBill;
    @ApiModelProperty("是否有费用")
    private Boolean hasFees;
    @ApiModelProperty("备注")
    private String remarks;
    @ApiModelProperty("运输关系")
    private List<Relation> relations;
    @ApiModelProperty("创建时间")
    private LocalDateTime createAt;
    @ApiModelProperty("创建人")
    private UserId createBy;
    @ApiModelProperty("租户ID")
    private TenantId tenantId;
    @ApiModelProperty("报价信息")
    private final List<Quotation> quotations = new ArrayList<>();


    public void addDevice(Device device) {
        this.device = device;
    }

    public void addQuote(Quote quote) {
        this.quote = quote;
    }

    public void addQuotation(Quotation quotation) {
        this.quotations.add(quotation);
    }

    public void addQuotations(List<Quotation> quotations) {
        if (CollectionUtils.isEmpty(quotations)) {
            return;
        }
        quotations.forEach(this::addQuotation);
    }

    public Set<String> getKeywords() {
        var keywords = new Keywords();
        keywords.add(this.contractNo);
        keywords.add(this.customer);
        this.waybills.forEach(waybill -> keywords.add(waybill.getContractNo()));
        return StreamSupport.stream(keywords.spliterator(), false)
                .collect(Collectors.toSet());
    }

    public boolean isCanQuote() {
        return BooleanUtils.isNotTrue(this.endBill);
    }

    private List<Quotation> getQuotations(TenantId tenantId) {
        return CallUtils.filter(Quotation::getTenantId, tenantId, this.quotations);
    }

    public List<CombineRelation> getRelations() {
        if (CollectionUtils.isEmpty(this.relations)) {
            return Collections.emptyList();
        }

        return this.relations
                .stream()
                .map(relation -> new CombineRelation(this, relation))
                .peek(relation -> {
                    var quotations = this.getQuotations(relation.getTenantId());
                    relation.addQuotations(quotations);
                })
                .collect(Collectors.toList());
    }

    public boolean getHasFees() {
        return null != this.getQuote();
    }
}
